//
// Created by shiboliu on 2025/11/15.
// 此定长内存池是不会将空间释放的，并不会造成内存泄漏。
// 这些空间由某个对象申请，不断地申请归还，只要进程是正常结束的，最后还是会归还所有空间。、
// 进程结束之后 OS 会自动回收整个进程的空间
//

#pragma once

#include <iostream>
#include <mutex>

using std::cout;
using std::endl;

#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#include <unistd.h>
#endif

//! \brief 向操作系统申请内存页
inline static void *SystemAlloc(size_t kpage) {
#ifdef _WIN32
    void *ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
    void *ptr = mmap(0, kpage << 13, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (ptr == MAP_FAILED) {
        ptr = nullptr;
    }
#endif
    if (ptr == nullptr) {
        throw std::bad_alloc();
    }
    return ptr;
}

template <typename T>
class ObjectPool {
  public:
    T *New() {             // 申请一个T类型的空间
        T *obj = nullptr;  // 最终返回的对象指针

        if (_freelist) {  // _freelist不为空，说明有归还的空闲空间
            // 头删
            void *next = *(void **)_freelist;
            obj = (T *)_freelist;
            _freelist = next;
        } else {  // _freelist为空，说明没有可重复利用的块
            if (_remanentBytes < sizeof(T)) {
                _remanentBytes = 128 * 1024;                          // 128KB
                _memory = (char *)SystemAlloc(_remanentBytes >> 13);  //  右移13位，申请16页
                if (_memory == nullptr) {
                    throw std::bad_alloc();
                }
            }

            obj = (T *)_memory;
            // 判断T大小，如果小于指针大小，就按指针大小切分
            size_t objSize = sizeof(T) < sizeof(void *) ? sizeof(void *) : sizeof(T);
            _memory += objSize;
            _remanentBytes -= objSize;
        }

        new (obj) T();  // 定位new，调用构造函数

        return obj;
    }

    void Delete(T *obj) {
        obj->~T();  // 显式调用析构函数

        *(void **)obj = _freelist;  // 新块指向旧块（或 空）
        _freelist = obj;            // 头指针指向新块
    }

  public:
    std::mutex _poolMtx;  // 防止ThreadCache申请时申请到空指针

  private:
    char *_memory{nullptr};    // 指向内存块的指针
    size_t _remanentBytes{0};  // 大块内存在切分过程中剩余字节数
    // void* 不能进行 算术运算 或 解引用 操作
    void *_freelist{nullptr};  // 自由链表，用来链接归还的空闲空间
};
